package com.yanqu.road.server.manger.activity.pawnshop;

import com.yanqu.road.dao.impl.activity.pawnshop.PawnshopTriggerDaoImpl;
import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.pawnshop.*;
import com.yanqu.road.entity.enums.activity.pawnshop.ePawnshopEventStatusType;
import com.yanqu.road.entity.enums.activity.pawnshop.ePawnshopEventType;
import com.yanqu.road.entity.enums.activity.pawnshop.ePawnshopItemType;
import com.yanqu.road.entity.enums.activity.pawnshop.ePawnshopStaffType;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.logic.bussiness.activity.PawnshopBussiness;
import com.yanqu.road.logic.helper.WeightHelper;
import com.yanqu.road.pb.activity.PawnshopProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.pawnshop.PawnshopModule;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.range.RangeInt;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class PawnshopMgr extends TempMgr {

    /**
     * 当铺配置
     **/
    public static PawnshopConfig config;

    private static Map<Integer, Map<Integer,PawnshopTriggerData>> activityTriggerDataMap;

    /**
     * 随机用的
     **/
    private static RandomHelper threadRandom = new RandomHelper();


    public static boolean randomFake(int eventType) {
        int next = threadRandom.next(0, 1000);
        return next >= config.buyNormalRate;
    }


    public static boolean isSellEventDoubleWeight(long coinUsable, long itemWealth) {
        return coinUsable * 1000 / (coinUsable + itemWealth) <= config.sellEventWeightDouble;
    }


    public static boolean isFoolSuccess() {
        int num = threadRandom.next(0, 1000);
        return num < config.sellEventFakeSuccessRate;
    }

    public static int getRefuseFakeAddPower(int level) {
        ConfPawnshop confPawnshop = config.getConfPawnshop(level);
        String refusePower = confPawnshop.getRefusePower();
        String[] arr = refusePower.split("\\|");
        List<Integer> powerList = new ArrayList<>();
        List<Integer> weightList = new ArrayList<>();
        for (String s : arr) {
            String[] strings = s.split(";");
            powerList.add(Integer.valueOf(strings[0]));
            weightList.add(Integer.valueOf(strings[1]));
        }
        int index = RandomHelper.getRandomIndexByWeight(weightList, new Random());
        return powerList.get(index);
    }

    public static long calcItemValuationPrice(PawnshopItem item, int politicsAddition, long modValue) {
        return calcItemValuationPrice(item.getBasePrice(), item.getRarity(), item.getStatusEffectPrice(), item.getEventAffixAddition(), item.getPersonAffixAddition(), politicsAddition, modValue);
    }

    /**
     * 售假是否被发现
     *
     * @param fakeStar
     * @return
     */
    public static boolean sellFakeSeeThrough(int fakeStar) {
        if (fakeStar > 0) {
            Integer value = config.fakeSeeThroughWeightMap.get(fakeStar);
            if (value == null) {
                return false;
            }
            int num = threadRandom.next(0, 1000);
            return num < value;
        }
        return false;
    }


    public static String randomItemDesc(int goodsId) {
        ConfPawnshopItem item = config.getConfPawnshopItem(goodsId);
        int charTextNum = item.getCharTextNum();
        if (charTextNum <= 0) {
            return "1";
        }
        return String.valueOf(threadRandom.next(0, charTextNum) + 1);
    }

    public static int randomFakeStar() {
        int index = RandomHelper.getRandomIndexByWeight(config.fakeStarFakeWeightList);
        return index + 1;

    }

    /**
     * 根据
     *
     * @return
     */
    public static int getFakeAffix() {
        return RandomHelper.getRandomIndexByWeight(config.fakeItemAffixWeightList);
    }

    public static int randomEventAdditionByFakeStar(int fakeStar) {
        List<Integer> list = config.fakeAffixLvMap.get(fakeStar);
        int lv = RandomHelper.getRandomIndexByWeight(list) + 1;
        return config.affixEventEffectMap.get(lv);
    }

    public static int randomPersonalAdditionByFakeStar(int fakeStar) {
        List<Integer> list = config.fakeAffixLvMap.get(fakeStar);
        int lv = RandomHelper.getRandomIndexByWeight(list) + 1;
        return config.affixPersonalEffectMap.get(lv);
    }

    public static boolean isInModAbsValue(long npcNextBid, long bidPrice, long modValue) {
        return Math.abs(npcNextBid - bidPrice) < modValue;
    }


    public static int randomNpcLv(int eventType, int level) {
        ConfPawnshop confPawnshop = config.getConfPawnshop(level);
        if (eventType == ePawnshopEventType.Buy.getValue()) {
            return RandomHelper.getRandomIndexByWeight(confPawnshop.getBuyNpcLv()) + 1;
        } else {
            return RandomHelper.getRandomIndexByWeight(confPawnshop.getSellNpcLv()) + 1;
        }
    }

    public static int getBrainwashAddPatient(UserPawnshop userPawnshop) {
        int staffLv = userPawnshop.getStaffLv(ePawnshopStaffType.Brainwasher.getValue());
        ConfPawnshopStaff staff = config.getConfPawnshopStaff(ePawnshopStaffType.Brainwasher.getValue(), staffLv);
        return staff.getParam1();
    }

    public static void syncTriggerData(int activityId, List<PawnshopProto.PawnshopTriggerDataMsg> dataList) {
        synchronized (activityTriggerDataMap) {
            Map<Integer, PawnshopTriggerData> dataMap = activityTriggerDataMap.get(activityId);
            if (dataMap == null) {
                dataMap = new ConcurrentHashMap<>();
                activityTriggerDataMap.put(activityId, dataMap);
            }
            for (PawnshopProto.PawnshopTriggerDataMsg msg : dataList) {
                int id = msg.getId();
                if (!dataMap.containsKey(id)) {
                    long userId = msg.getUserId();
                    long triggerTime = msg.getTriggerTime();
                    PawnshopTriggerData data = new PawnshopTriggerData();
                    data.setActivityId(activityId);
                    data.setUse(false);
                    data.setId(id);
                    data.setUserId(userId);
                    data.setTriggerTime(triggerTime);
                    data.setUseTime(0);
                    data.setInsertOption();
                    dataMap.put(id, data);
                }
            }
        }
    }

    public static boolean canTriggerSpecialEvent(int activityId,long userId) {
        Map<Integer, PawnshopTriggerData> dataMap = activityTriggerDataMap.get(activityId);
        if (dataMap == null) {
            return false;
        }
        for (PawnshopTriggerData data : dataMap.values()) {
            if (data.getUserId() == userId && !data.isUse()) {
                data.setUseTime(System.currentTimeMillis());
                data.setUse(true);
                return true;
            }
        }
        return false;
    }


    @Override
    public boolean reloadData() throws Exception {
        // TODO 自动生成的方法存根
        activityTriggerDataMap = new ConcurrentHashMap<>();
        if (config != null) {
            Map<Integer, PawnshopTriggerData> dataMap = new PawnshopTriggerDaoImpl().getPawnshopTriggerData(config.getActivityId());
            activityTriggerDataMap.put(config.getActivityId(), dataMap);
        }
        return true;
    }

    @Override
    public boolean init() throws Exception {
        // TODO 自动生成的方法存根
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        // TODO 自动生成的方法存根
        return false;
    }

    @Override
    public boolean save() {
        // 保持数据
        if (activityTriggerDataMap != null) {
            for (Map<Integer, PawnshopTriggerData> dataMap : new ArrayList<>(activityTriggerDataMap.values())) {
                for (PawnshopTriggerData data : new ArrayList<>(dataMap.values())) {
                    if (data.isInsertOption()) {
                        new PawnshopTriggerDaoImpl().add(data);
                    } else if (data.isUpdateOption()) {
                        new PawnshopTriggerDaoImpl().update(data);
                    }
                }
            }
        }
        return true;
    }

    /**
     * 重新加载活动数据
     */
    public static void reloadActivityData() {
        //getLogger().info("PawnshopMgr.reloadActivityData start");

        PawnshopConfig tmpConfig = new PawnshopConfig();
        // 获取进行中的活动信息
        List<ActivityInfo> openActivityInfoList = NormalActivityMgr
                .getOpenActivityInfoList(eActivityType.PawnshopActivity.getValue());
        if (openActivityInfoList.isEmpty()) {
            //getLogger().info("no WishPool in show time");
            return;
        }
        tmpConfig.setActivityInfo(openActivityInfoList.get(0));

        // 感觉活动ID获取配置
        int activityId = tmpConfig.getActivityId();
        tmpConfig.setConfPawnshopList(PawnshopBussiness.getConfPawnshopList(activityId));
        tmpConfig.setConfPawnshopStaffList(PawnshopBussiness.getConfPawnshopStaffList(activityId));
        tmpConfig.setConfPawnshopItemList(PawnshopBussiness.getConfPawnshopItemList(activityId));
        tmpConfig.setConfPawnshopItemLvList(PawnshopBussiness.getConfPawnshopItemLvList(activityId));
        tmpConfig.setConfPawnshopEventMap(PawnshopBussiness.getConfPawnshopEventMap(activityId));

        // 解析当铺的参数配置
        Map<String, ActivityConfig> configMap = NormalActivityMgr.getActivityConfigMap(activityId);
        tmpConfig.parseParam(configMap);

        config = tmpConfig;
        // 在线玩家加载活动数据
        reloadPlayerData();

        //getLogger().info("PawnshopMgr.reloadActivityData end");
    }

    /**
     * 在线玩家加载活动数据
     */
    public static void reloadPlayerData() {
        if (isActivityInShowTime()) {
            int activityId = getShowTimeActivityId();
            for (GamePlayer player : GamePlayerMgr.getCopyPlayerMap().values()) {
                if (SystemOpenMgr.systemOpen(player, eSystemId.PawnshopActivity.getValue())) {
                    PawnshopModule module = player.getModule(PawnshopModule.class);
                    if (module.getUserPawnshop() == null || module.getActivityId() != activityId) {
                        module.initUserData();
                        module.loginSendPower();
                    }
                }
            }
        }
    }

    /**
     * 获取展示中的活动ID（0表示没活动）
     */
    public static int getShowTimeActivityId() {
        return config == null ? 0 : config.getActivityId();
    }

    /**
     * 是否在展示时间内
     */
    public static boolean isActivityInShowTime() {
        if (config == null) {
            return false;
        }
        return ActivityMgr.activityInShowTime(config.getActivityInfo());
    }

    /**
     * 是否在操作时间内
     */
    public static boolean isActivityInTime() {
        return ActivityMgr.activityInTime(config.getActivityInfo());
    }

    /**
     * 是否在清空道具时间内
     */
    public static boolean isActivityInClearTime() {
        if (config == null) {
            return false;
        }
        return  ActivityMgr.activityInRewardPeriod(config.getActivityInfo());
    }

    /**
     * 检测员工类型值
     *
     * @param staffType
     * @return
     */
    public static boolean checkStaffType(int staffType) {
        return staffType > 0 && staffType < 4;
    }

    /**
     * 检测员工能否升级
     *
     * @param pawnshopLv
     * @param staffType
     * @param level
     * @return
     */
    public static boolean checkStaffCanUpgrade(int pawnshopLv, int staffType, int level) {
        ConfPawnshopStaff confPawnshopStaff = config.getConfPawnshopStaff(staffType, level + 1);
        if (null == confPawnshopStaff) {
            return false;
        }
        return confPawnshopStaff.getUnlockLevel() <= pawnshopLv;
    }


    /**
     * 生成物件数据
     */
    public static PawnshopItem createItem(long itemId, int levelPS, ePawnshopItemType type, UserPawnshop userPawnshop, int fakeStar,boolean special) {
        PawnshopItem item = new PawnshopItem();
        ConfPawnshop confPawnshop = config.getConfPawnshop(levelPS);
        if (confPawnshop != null) {
            int itemLv = 0;
            int goodsId = 0;
            int stoneGoodsId = 0;
            int stoneLv = 0;
            long basePrice = 0;
            int statusEffectPrice = 0;
            int eventAffixAddition = 0;
            int personAffixAddition = 0;
            String descNo = "1";
            if (type == ePawnshopItemType.Item) {
                // 随机物件等级
                itemLv = RandomHelper.getRandomKeyByWeight(confPawnshop.getItemLvWeight());
                goodsId = config.getGoodsId(ePawnshopItemType.Item.getValue(), itemLv);
                descNo = randomItemDesc(goodsId);
            } else if (type == ePawnshopItemType.Gemstone) {
                // 随机原石等级
                stoneLv = RandomHelper.getRandomKeyByWeight(confPawnshop.getGemstoneLvWeight());
                // 随机原石
                stoneGoodsId = config.getGoodsId(ePawnshopItemType.Stone.getValue(), stoneLv);
                ConfPawnshopItem stoneConfig = config.getConfPawnshopItem(stoneGoodsId);
                RandomGemstone randomGemstone = randomGemstone(stoneLv, stoneConfig);
                int gemstoneLv = randomGemstone.getLv();
                goodsId = randomGemstone.getGoodsId();
                if (special) {
                    gemstoneLv = userPawnshop.getLevel() + config.specialGemstoneAddLv;
                    goodsId = config.specialGemstoneId;
                    if (gemstoneLv <= 0) {
                        gemstoneLv = 1;
                    } else if (gemstoneLv > getGemstoneItemMaxLv()) {
                        gemstoneLv = getGemstoneItemMaxLv();
                    }
                    item.setSpecial(true);
                }
                item.setStatus(randomGemstone.getStatus());
                item.setRarity(randomGemstone.getRarity());
                itemLv = gemstoneLv;
                descNo = randomItemDesc(stoneGoodsId);
            }
            int sn1 = 0;
            if (type != ePawnshopItemType.Gemstone) {
                sn1 = config.affixSnRangeMap.get(1).random();
            }

            int sn3 = 0;
            int sn4 = 0;
            int sn2 = 0;
            if (randomSn2() && type != ePawnshopItemType.Gemstone) {
                sn2 = config.affixSnRangeMap.get(2).random();
            }
            int eventAffixRate = 0;
            int personAffixRate = 0;
            int rarity = 1;
            int status = 1;
            ConfPawnshopItemLv confItemLv = config.getConfPawnshopItemLvMap().get(itemLv);
            if (fakeStar > 0) {
                //假货事件随的词条走其他逻辑
                 sn3 = PawnshopMgr.config.affixSnRangeMap.get(3).random();
                 sn4 = PawnshopMgr.randomSn4(goodsId);
                int fakeAffix = PawnshopMgr.getFakeAffix();
                if (fakeAffix == 0) {
                    //人物词条
                    item.setAffixSn3(sn3);
                    item.setPersonAffixAddition(PawnshopMgr.randomPersonalAdditionByFakeStar(fakeStar));
                } else if (fakeAffix == 1) {
                    //事件词条
                    item.setAffixSn4(sn4);
                    item.setPersonAffixAddition(PawnshopMgr.randomEventAdditionByFakeStar(fakeStar));
                } else {
                    //人物 + 事件 词条
                    item.setAffixSn3(sn3);
                    item.setPersonAffixAddition(PawnshopMgr.randomPersonalAdditionByFakeStar(fakeStar));
                    item.setAffixSn4(sn4);
                    item.setPersonAffixAddition(PawnshopMgr.randomEventAdditionByFakeStar(fakeStar));
                }
            } else {
                eventAffixRate = confItemLv.getEventAffixRate();
                personAffixRate = confItemLv.getPersonAffixRate();
                if (randomSn3(eventAffixRate) && type != ePawnshopItemType.Gemstone) {
                    sn3 = config.affixSnRangeMap.get(3).random();
                }
                if (hasSn4(personAffixRate) && type != ePawnshopItemType.Gemstone) {
                    sn4 = randomSn4(goodsId);
                }
                if (sn3 > 0) {
                    eventAffixAddition = config.getEventAffixAddition();
                }
                if (sn4 > 0) {
                    personAffixAddition = config.getPersonalAffixAddition();
                }
            }
            basePrice = calcBasePrice(itemLv);
            statusEffectPrice = getStatusEffectPrice(status);
            item.setItemId(itemId);
            item.setGoodsId(goodsId);
            item.setStoneGoodsId(stoneGoodsId);
            item.setStoneLv(stoneLv);
            item.setLevel(itemLv);
            if (type != ePawnshopItemType.Gemstone) {
                rarity = RandomHelper.getRandomKeyByWeight(confItemLv.getRarityWeight());
                status = RandomHelper.getRandomKeyByWeight(confItemLv.getStatusWeight());
                item.setRarity(rarity);
                item.setStatus(status);
            }
            item.setCoinBuy(0);
            item.setAffixSn1(sn1);
            item.setAffixSn2(sn2);
            item.setAffixSn3(sn3);
            item.setAffixSn4(sn4);
            item.setBasePrice(basePrice);
            item.setStatusEffectPrice(statusEffectPrice);
            item.setEventAffixAddition(eventAffixAddition);
            item.setPersonAffixAddition(personAffixAddition);
            item.setDescNo(descNo);
        }
        return item;
    }



    private static RandomGemstone randomGemstone(int stoneLv, ConfPawnshopItem stoneConfig) {
        List<Integer> weightList = new ArrayList<>();
        List<Integer> lvList = new ArrayList<>();
        String[] arr = stoneConfig.getParam().split("\\|");
        for (String s : arr) {
            String[] strings = s.split(";");
            weightList.add(Integer.valueOf(strings[1]));
            lvList.add(Integer.valueOf(strings[0]));
        }
        int index = RandomHelper.getRandomIndexByWeight(weightList);
        Integer lv = lvList.get(index);
        int gemstoneLv = stoneLv + lv;
        if (gemstoneLv <= 0) {
            gemstoneLv = 1;
        } else if (gemstoneLv > getGemstoneItemMaxLv()) {
            gemstoneLv = getGemstoneItemMaxLv();
        }

        List<Integer> list = new ArrayList<>();
        Map<Integer, ConfPawnshopItem> pawnshopItemMap = config.getConfPawnshopItemMap();
        for (ConfPawnshopItem item : pawnshopItemMap.values()) {
            if (item.getType() == ePawnshopItemType.Gemstone.getValue()) {
                String[] split = item.getLevelRange().split(";");
                if (split.length >= 2) {
                    int min = Integer.parseInt(split[0]);
                    int max = Integer.parseInt(split[1]);
                    if (lv >= min && lv <= max) {
                        list.add(item.getId());
                    }
                }
            }
        }

        Integer goodsId = list.get(RandomHelper.getRandomIndexByWeight(list));

        List<Integer> statusList = new ArrayList<>();
        List<Integer> statusWeightList = new ArrayList<>();
        for (int i = 0; i < config.gemstoneStatusRangeList.size(); i++) {
            RangeInt rangeInt = config.gemstoneStatusRangeList.get(i);
            if (gemstoneLv >= rangeInt.min && gemstoneLv <= rangeInt.max) {
                statusList.add(i);
                statusWeightList.add(config.gemstoneStatusWeightList.get(i));
            }
        }

        ConfPawnshopItem confPawnshopItem = config.getConfPawnshopItem(goodsId);
        int statusIndex = RandomHelper.getRandomIndexByWeight(statusWeightList);
        Integer status = statusList.get(statusIndex) + 1;
        return new RandomGemstone(gemstoneLv,goodsId,status,Integer.parseInt(confPawnshopItem.getParam()));
    }

    private static int getGemstoneItemMaxLv() {
        int max = 0;
        for (RangeInt anInt : config.gemstoneStatusRangeList) {
            if (max < anInt.max) {
                max = anInt.max;
            }
        }
        return max;
    }

    public static int randomSn4(int goodsId) {
        return Integer.parseInt(randomItemDesc(goodsId));
    }

    private static boolean hasSn4(int personAffixRate) {
        return threadRandom.next(0, 1000) < personAffixRate;
    }

    private static boolean randomSn3(int eventAffixRate) {
        return threadRandom.next(0, 1000) < eventAffixRate;
    }

    public static boolean randomSn2() {
        int num = threadRandom.next(0, 1000);
        return num < config.affix2Rate;
    }

    /**
     * 计算售卖物件估价
     *
     * @param base                随机出来的基础价格
     * @param rarity              稀有度
     * @param statusEffectPrice   状态浮动
     * @param eventAffixAddition  事件词条加成
     * @param personAffixAddition 人物词条加成
     * @param politicsAddition    时事加成
     * @return
     */
    public static long calcItemValuationPrice(long base, int rarity, int statusEffectPrice, int eventAffixAddition, int personAffixAddition, int politicsAddition, long modValue) {
        BigDecimal rarityRate = BigDecimal.ZERO;
        if (rarity != 0) {
            rarityRate = new BigDecimal(config.rarityPriceRateMap.get(rarity)).divide(new BigDecimal("1000"), 10, BigDecimal.ROUND_UP);
        }
        BigDecimal statusRate = new BigDecimal(statusEffectPrice).divide(BigDecimal.valueOf(1000), 10, BigDecimal.ROUND_UP);
        BigDecimal ciTiaoParam = new BigDecimal(eventAffixAddition + personAffixAddition).divide(BigDecimal.valueOf(1000), 10, BigDecimal.ROUND_UP);
        BigDecimal param = BigDecimal.ONE.add(rarityRate).add(statusRate).add(ciTiaoParam);
        long value = new BigDecimal(base).multiply(param).multiply(BigDecimal.ONE.add(new BigDecimal(politicsAddition/1000.0))).setScale(0, BigDecimal.ROUND_UP).longValue();
        //getLogger().info("base {}， rarity {}, statusEffectPrice {}, eventAffixAddition {}, personAffixAddition {}, politicsAddition {}, ValuationPrice {}", base, config.rarityPriceRateMap.get(rarity), statusEffectPrice, eventAffixAddition, personAffixAddition, politicsAddition, value);
        return quZheng(value, modValue);
    }

    public static long quZheng(long oriPrice, long modValue) {

        if (oriPrice <= 1000) {
            return oriPrice;
        }

        String str = String.valueOf(oriPrice);
        String substring = str.substring(0, 3);
        String lastStr = str.substring(3);
        Long lastValue = Long.valueOf(lastStr);
        Integer tempValue = Integer.valueOf(substring);
        if (lastValue > 0) {
            tempValue++;
        }
        int length = lastStr.length();
        StringBuilder s = new StringBuilder(String.valueOf(tempValue));
        for (int i = 0; i < length; i++) {
            s.append("0");
        }
        return Long.valueOf(s.toString());
    }

    /**
     * 获取物件状态影响价格
     *
     * @param status
     * @return
     */
    public static int getStatusEffectPrice(int status) {
        RangeInt rangeInt = config.statusPriceRangeMap.get(status);
        return rangeInt.random();
    }

    public static long calcBasePrice(int lv) {
        ConfPawnshopItemLv confItemLv = config.getConfPawnshopItemLvMap().get(lv);
        String priceBase = confItemLv.getPriceBase();
        String[] strArray = priceBase.split(";");
        long minValue = Long.parseLong(strArray[0].trim());
        long maxValue = Long.parseLong(strArray[1].trim());
        double v = threadRandom.nextDouble(minValue, maxValue);
        return (long)v;
    }

    //=============== 售卖事件 ==================

    /**
     * 计算售卖事件首次出价
     *
     * @return
     */
    public static long initSellFirstPrice(UserPawnshop userPawnshop, UserPawnshopEvent event) {
        int npcLv = event.getNpc().getLv();
        long modValue = getModValue(userPawnshop);
        long valuationPrice = event.getValuationPrice();
        int k1 = config.sellNpcParamMap.get(npcLv).get(0);
        int k2 = config.sellNpcParamMap.get(npcLv).get(1);
        double randomValue = threadRandom.next(1, 1000) / 1000.0;
        double param = k1 + (k2 - k1) * randomValue;
        double x = valuationPrice * param / 1000;
        long value = (long) Math.ceil(x);
        //getLogger().info("valuationPrice {}, k1: {}, k2: {},randomValue {}, firstPrice: {}", valuationPrice, k1, k2, randomValue, value);
        return quZheng(value, modValue);
    }

    public static long initStonePrice(UserPawnshop userPawnshop,int npcLv,long valuationPrice) {
        long modValue = getModValue(userPawnshop);
        int k1 = config.sellNpcParamMap.get(npcLv).get(0);
        int k2 = config.sellNpcParamMap.get(npcLv).get(1);
        double randomValue = threadRandom.next(1, 1000) / 1000.0;
        double param = k1 + (k2 - k1) * randomValue;
        double x = valuationPrice * param / 1000;
        long value = (long) Math.ceil(x);
        //getLogger().info("valuationPrice {}, k1: {}, k2: {},randomValue {}, firstPrice: {}", valuationPrice, k1, k2, randomValue, value);
        return quZheng(value, modValue);
    }

    /**
     * 计算售卖事件顾客最高买入价
     *
     * @return
     */
    public static long initSellMaxPrice(UserPawnshop userPawnshop, UserPawnshopEvent event) {
        int npcLv = event.getNpc().getLv();
        long valuationPrice = event.getValuationPrice();
        int k3 = config.sellNpcParamMap.get(npcLv).get(2);
        int k4 = config.sellNpcParamMap.get(npcLv).get(3);
        double randomValue = threadRandom.next(1, 1000) / 1000.0;
        double param = k3 + (k4 - k3) * randomValue;
        double x = valuationPrice * param / 1000;
        long value = (long) Math.ceil(x);
        //getLogger().info("valuationPrice {}, k3: {}, k4: {},randomValue {}, maxPrice: {}", valuationPrice, k3, k4, randomValue, value);
        return value;
    }

    public static long initSellWantPrice(UserPawnshop userPawnshop, UserPawnshopEvent event) {
        int npcLv = event.getNpc().getLv();
        int w = config.sellNpcParamMap.get(npcLv).get(6);
        PawnshopItem item = event.getItemList().get(0);
        long basePrice = event.getNpcBid();
        long maxPrice = event.getMaxPrice();
        double v = basePrice + (maxPrice - basePrice) * w / 1000.0;
        long value = (long) Math.ceil(v);
        //getLogger().info("basePrice {}, maxPrice {}, w {}, value {}", basePrice, maxPrice, w, value);
        return value;
    }


    public static PawnshopBidPrice calcSellBidPrice(UserPawnshop userPawnshop, UserPawnshopEvent event, int index) {
        long maxPrice = event.getMaxPrice();
        long modValue = getModValue(userPawnshop);
        long wantPrice = event.getNpcWantPrice();
        int h1 = config.sellPlayerParamMap.get(index).get(0);
        int h2 = config.sellPlayerParamMap.get(index).get(1);
        int d1 = config.sellPlayerParamMap.get(index).get(2);
        int d2 = config.sellPlayerParamMap.get(index).get(3);
        int t1 = config.sellPlayerParamMap.get(index).get(4);
        int t2 = config.sellPlayerParamMap.get(index).get(5);
        double f = threadRandom.next(1, 1000) / 1000.0;
        double value = (maxPrice - wantPrice) * (h1 + (h2 - h1) * f) / 1000 + wantPrice;
        long price = quZheng((long) Math.ceil(value), modValue);
        //getLogger().info("maxPrice {}, wantPrice  {}, f {}, price {}", maxPrice, wantPrice, f, price);
        long npcPrice = event.getNpcBid();
        int patient = event.getPatient();
        double tempProbability = t1 / 1000.0 + Math.pow(1.0 * (maxPrice - price) / (maxPrice - npcPrice), t2 / 1000.0);
        int probability = (int) Math.ceil(Math.min(1.0, tempProbability) * 100);

        int reducePatient = (int) Math.ceil(d1 / 1000.0 + patient * (100 - probability) * d2 / 1000.0 / 100);
        return new PawnshopBidPrice(probability, reducePatient, price);
    }

    public static List<PawnshopBidPrice> sellBidPriceList(UserPawnshop userPawnshop, UserPawnshopEvent userPawnshopEvent) {
        List<PawnshopBidPrice> list = new ArrayList<>();
        int size = config.sellPlayerParamMap.size();
        for (int i = 0; i < size; i++) {
            PawnshopBidPrice price = calcSellBidPrice(userPawnshop, userPawnshopEvent, i + 1);
            list.removeIf(next -> next.getPrice() == price.getPrice());
            list.add(price);
        }
        return list;
    }


    /**
     * 售卖事件，顾客重新出价
     *
     * @return
     */
    public static long sellEventResetPrice(UserPawnshop userPawnshop, UserPawnshopEvent event) {
        long oldWantPrice = event.getNpcWantPrice();
        long npcLastPrice = event.getNpcBid();
        int npcLv = event.getNpc().getLv();
        long modValue = getModValue(userPawnshop);
        int l1 = config.sellNpcParamMap.get(npcLv).get(4);
        int l2 = config.sellNpcParamMap.get(npcLv).get(5);
        int patient = event.getPatient();
        long userBid = event.getUserBid();

        long wantPrice = (long) Math.ceil((oldWantPrice - npcLastPrice) * (patient / 100.0 - 1) * l1 / 1000 + oldWantPrice);
        //getLogger().info("resetSellWantPrice,  oldWantPrice: {}, npcLastPrice {}, patient {}, l1 {}",oldWantPrice,npcLastPrice,patient,l1);
        double tempValue = (long) Math.ceil((wantPrice - npcLastPrice) * (patient / 100.0) * l2 / 1000 + npcLastPrice);
        long value = (long) Math.ceil(tempValue);
        //getLogger().info("resetSellNpcBid,  wantPrice: {}, npcLastPrice {}, patient {}, l2 {}",wantPrice,npcLastPrice,patient,l1);
        event.setNpcWantPrice(wantPrice);
        event.setNpcBid(value);
        event.setMaxPrice(event.getUserBid());
        //getLogger().info("curPrice {},lastPrice {},patient {}, calcPrice {}", userBid, npcLastPrice, patient, tempValue);
        return quZheng(value, modValue);
    }


    public static long getModValue(UserPawnshop userPawnshop) {
        return 1;
    }


    //===========  购买事件  ================

    /**
     * 计算售卖事件首次出价
     *
     * @return
     */
    public static long initBuyFirstPrice(UserPawnshop userPawnshop, UserPawnshopEvent event) {
        int npcLv = event.getNpc().getLv();
        long modValue = getModValue(userPawnshop);
        long valuationPrice = event.getValuationPrice();
        int k1 = config.buyNpcParamMap.get(npcLv).get(0);
        int k2 = config.buyNpcParamMap.get(npcLv).get(1);
        double randomValue = threadRandom.next(1, 1000) / 1000.0;
        double param = k1 + (k2 - k1) * randomValue;
        double x = valuationPrice * param / 1000;
        long value = (long) Math.ceil(x);
        //getLogger().info("valuationPrice {}, k1: {}, k2: {},randomValue {}, firstPrice: {}", valuationPrice, k1, k2, randomValue, value);
        return quZheng(value, modValue);
    }

    /**
     * 计算售卖事件顾客最高买入价
     *
     * @return
     */
    public static long initBuyMaxPrice(UserPawnshop userPawnshop, UserPawnshopEvent event) {
        int npcLv = event.getNpc().getLv();
        long valuationPrice = event.getValuationPrice();
        int k3 = config.buyNpcParamMap.get(npcLv).get(2);
        int k4 = config.buyNpcParamMap.get(npcLv).get(3);
        double randomValue = threadRandom.next(1, 1000) / 1000.0;
        double param = k3 + (k4 - k3) * randomValue;
        double x = valuationPrice * 1000 / param;
        long value = (long) Math.ceil(x);
        //getLogger().info("valuationPrice {}, k3: {}, k4: {},randomValue {}, maxPrice: {}", valuationPrice, k3, k4, randomValue, value);
        return value;
    }

    public static long initBuyWantPrice(UserPawnshop userPawnshop, UserPawnshopEvent event) {
        int npcLv = event.getNpc().getLv();
        int w = config.buyNpcParamMap.get(npcLv).get(6);
        PawnshopItem item = event.getItemList().get(0);
        long basePrice = event.getNpcBid();
        long maxPrice = event.getMaxPrice();
        double v = basePrice + (maxPrice - basePrice) * w / 1000.0;
        long value = (long) Math.ceil(v);
        //getLogger().info("basePrice {}, maxPrice {}, w {}, value {}", basePrice, maxPrice, w, value);
        return value;
    }


    public static PawnshopBidPrice calcBuyBidPrice(UserPawnshop userPawnshop, UserPawnshopEvent event, int index) {
        long maxPrice = event.getMaxPrice();
        long modValue = getModValue(userPawnshop);
        long wantPrice = event.getNpcWantPrice();
        int h1 = config.buyPlayerParamMap.get(index).get(0);
        int h2 = config.buyPlayerParamMap.get(index).get(1);
        int d1 = config.buyPlayerParamMap.get(index).get(2);
        int d2 = config.buyPlayerParamMap.get(index).get(3);
        int t1 = config.buyPlayerParamMap.get(index).get(4);
        int t2 = config.buyPlayerParamMap.get(index).get(5);
        double f = threadRandom.next(1, 1000) / 1000.0;
        double value = (maxPrice - wantPrice) * (h1 + (h2 - h1) * f) / 1000 + wantPrice;
        long price = quZheng((long) Math.ceil(value), modValue);
        //getLogger().info("maxPrice {}, wantPrice  {}, f {}, price {}", maxPrice, wantPrice, f, price);
        long npcPrice = event.getNpcBid();
        int patient = event.getPatient();
        double tempProbability = t1 / 1000.0 + Math.pow(1.0 * (maxPrice - price) / (maxPrice - npcPrice), t2 / 1000.0);
        int probability = (int) Math.ceil(Math.min(1.0, tempProbability) * 100);


        int reducePatient = (int) Math.ceil(d1 / 1000.0 + patient * (100 - probability) * d2 / 1000.0 / 100);
        return new PawnshopBidPrice(probability, reducePatient, price);
    }

    public static List<PawnshopBidPrice> buyBidPriceList(UserPawnshop userPawnshop, UserPawnshopEvent userPawnshopEvent) {
        List<PawnshopBidPrice> list = new ArrayList<>();
        int size = config.buyPlayerParamMap.size();
        for (int i = 0; i < size; i++) {
            PawnshopBidPrice price = calcBuyBidPrice(userPawnshop, userPawnshopEvent, i + 1);
            list.removeIf(next -> next.getPrice() == price.getPrice());
            list.add(price);
        }
        return list;
    }


    /**
     * 售卖事件，顾客重新出价
     *
     * @return
     */
    public static long buyEventResetPrice(UserPawnshop userPawnshop, UserPawnshopEvent event) {
        long oldWantPrice = event.getNpcWantPrice();
        long npcLastPrice = event.getNpcBid();
        int npcLv = event.getNpc().getLv();
        long modValue = getModValue(userPawnshop);
        int l1 = config.buyNpcParamMap.get(npcLv).get(4);
        int l2 = config.buyNpcParamMap.get(npcLv).get(5);
        int patient = event.getPatient();
        long userBid = event.getUserBid();

        long wantPrice = (long) Math.ceil((oldWantPrice - npcLastPrice) * (patient / 100.0 - 1) * l1 / 1000 + oldWantPrice);
        //getLogger().info("resetSellWantPrice,  oldWantPrice: {}, npcLastPrice {}, patient {}, l1 {}",oldWantPrice,npcLastPrice,patient,l1);
        double tempValue = (long) Math.ceil((wantPrice - npcLastPrice) * (patient / 100.0) * l2 / 1000 + npcLastPrice);
        long value = (long) Math.ceil(tempValue);
        //getLogger().info("resetSellNpcBid,  wantPrice: {}, npcLastPrice {}, patient {}, l2 {}",wantPrice,npcLastPrice,patient,l1);
        event.setNpcWantPrice(wantPrice);
        event.setNpcBid(value);
        event.setMaxPrice(event.getUserBid());
        //getLogger().info("curPrice {},lastPrice {},patient {}, calcPrice {}", userBid, npcLastPrice, patient, tempValue);
        return quZheng(value, modValue);
    }


    /**
     * 是否触发时事
     *
     * @param triggerRate
     * @return
     */
    public static boolean isTriggerPolitics(int triggerRate) {
        int randomValue = threadRandom.next(0, 1000);
        return triggerRate > randomValue;
    }

    /**
     * 获取随机时事
     *
     * @return
     */
    public static ConfPawnshopEvent getRandomConfPawnshopEvent() {
        List<ConfPawnshopEvent> dataList = new ArrayList<>(config.getConfPawnshopEventMap().values());
        int totalWeight = 0;
        for (ConfPawnshopEvent confPawnshopEvent : dataList) {
            totalWeight += confPawnshopEvent.getWeight();
        }
        int randomValue = threadRandom.next(0, totalWeight);
        int tempValue = 0;
        for (ConfPawnshopEvent confPawnshopEvent : dataList) {
            tempValue += confPawnshopEvent.getWeight();
            if (tempValue > randomValue) {
                return confPawnshopEvent;
            }
        }
        return null;
    }

    /**
     * 获取随机时事加成
     *
     * @return
     */
    public static int getRandomPoliticsAddition(ConfPawnshopEvent confPawnshopEvent) {
        if (null == confPawnshopEvent) {
            return 0;
        }
        return WeightHelper.getRandomValue(confPawnshopEvent.getWeightItemList()).intValue();
    }

    /**
     * 获取物件修复后状态
     *
     * @param repairLv
     * @return
     */
    public static int getItemRepairStatus(int repairLv) {
        ConfPawnshopStaff confPawnshopStaff = config.getConfPawnshopStaff(ePawnshopStaffType.Repairer.getValue(), repairLv);
        if (null == confPawnshopStaff) {
            return 0;
        }
        return WeightHelper.getRandomValue(confPawnshopStaff.getWeightItemList()).intValue();
    }

    /**
     * 获取物件伪造后星级
     *
     * @param fakeLv
     * @return
     */
    public static int getItemFakeStar(int fakeLv) {
        ConfPawnshopStaff confPawnshopStaff = config.getConfPawnshopStaff(ePawnshopStaffType.Faker.getValue(), fakeLv);
        if (null == confPawnshopStaff) {
            return 0;
        }
        return WeightHelper.getRandomValue(confPawnshopStaff.getWeightItemList()).intValue();
    }

    /**
     * 典当是否赎回
     *
     * @return
     */
    public static boolean isHockRedemption() {
        int randomValue = threadRandom.next(0, 1000);
        return config.getHockRedemptionRate() > randomValue;
    }

    /**
     * 获取赎当价格
     *
     * @return
     */
    public static long getHockRedemptionPrice(long hockPrice) {
        long redemptionPrice = hockPrice;
        double interest = redemptionPrice;
        interest = Math.ceil(interest * config.getHockInterest() / 1000);
        redemptionPrice = (long) (hockPrice + interest);
        return redemptionPrice;
    }

    public static void test() {
     /*   List<String> list = new ArrayList<>();
        RandomHelper randomHelper = new RandomHelper();
        int[][] arr = new int[13][4];
        arr[0] = new int[]{0, 0, 0, 0};
        arr[1] = new int[]{1, 1, 1, 1};
        arr[2] = new int[]{2, 2, 2, 2};
        arr[3] = new int[]{3, 3, 3, 3};
        arr[4] = new int[]{4, 4, 4, 4};
        arr[5] = new int[]{0, 1, 2, 3};
        arr[6] = new int[]{1, 2, 3, 4};
        arr[7] = new int[]{2, 3, 4, 4};
        arr[8] = new int[]{1, 2, 2, 3};
        arr[9] = new int[]{2, 3, 4, 4};
        arr[10] = new int[]{2, 1, 1, 1};
        arr[11] = new int[]{3, 2, 1, 0};
        arr[12] = new int[]{4, 3, 2, 1};
        for (int[] ints : arr) {
            int sellTimes = 0;
            int totalTimes = 0;
            long totalMoney = 0;
            for (int i = 0; i < 10000; i++) {
                UserPawnshopEvent userPawnshopEvent = new UserPawnshopEvent();
                userPawnshopEvent.setPatient(100);
                // 生成NPC数据
                PawnshopNpc npc = new PawnshopNpc();
                int eventType = ePawnshopEventType.Sell.getValue();
                int levelPS = 1;
                npc.setLv(PawnshopMgr.randomNpcLv(eventType, 1));
                // 生成1个物件
                List<PawnshopItem> itemList = new ArrayList<>();

                PawnshopItem item = new PawnshopItem();

                UserPawnshop userPawnshop = new UserPawnshop();
                userPawnshop.setLevel(1);
                itemList.add(item);
                userPawnshopEvent.setItemList(itemList);
                userPawnshopEvent.setWashTime(0);
                userPawnshopEvent.setUserBid(0);
                userPawnshopEvent.setNpc(npc);
                userPawnshopEvent.setSchoolType(eventType);

                List<PawnshopBidPrice> bidPriceList;
                long valuationPrice = 10000;
                userPawnshopEvent.setValuationPrice(valuationPrice);
                if (eventType == ePawnshopEventType.Sell.getValue()) {
                    userPawnshopEvent.setNpcBid(PawnshopMgr.initSellFirstPrice(userPawnshop, userPawnshopEvent));
                    userPawnshopEvent.setMaxPrice(PawnshopMgr.initSellMaxPrice(userPawnshop, userPawnshopEvent));
                    //第一次出价 需要现有最高价格
                    userPawnshopEvent.setNpcWantPrice(PawnshopMgr.initSellWantPrice(userPawnshop, userPawnshopEvent));
                    bidPriceList = PawnshopMgr.sellBidPriceList(userPawnshop, userPawnshopEvent);
                } else {
                    userPawnshopEvent.setNpcBid(PawnshopMgr.initBuyFirstPrice(userPawnshop, userPawnshopEvent));
                    userPawnshopEvent.setMaxPrice(PawnshopMgr.initBuyMaxPrice(userPawnshop, userPawnshopEvent));
                    //第一次出价 需要现有最高价格
                    userPawnshopEvent.setNpcWantPrice(PawnshopMgr.initBuyWantPrice(userPawnshop, userPawnshopEvent));
                    bidPriceList = PawnshopMgr.buyBidPriceList(userPawnshop, userPawnshopEvent);
                }
                int index = 0;
                userPawnshopEvent.setPriceList(bidPriceList);
                totalTimes++;
                PawnshopBidResult result = eventBid(userPawnshopEvent, userPawnshop, ints[index], randomHelper);
                while (result.getDealStatus() == ePawnshopEventStatusType.NORMAL.getValue()) {
                    result = eventBid(userPawnshopEvent, userPawnshop, 0, randomHelper);
                    totalTimes++;
                    index++;
                }
                if (result.getDealStatus() == ePawnshopEventStatusType.DEAL.getValue()) {
                    long userBid = result.getUserBid();
                    totalMoney += userBid;
                    sellTimes++;
                }
            }
            list.add(totalMoney + "    " + sellTimes + "   " + totalTimes);
        }
        for (String s : list) {
            System.out.println(s);
        }*/
    }

    private static PawnshopBidResult eventBid(UserPawnshopEvent userPawnshopEvent, UserPawnshop userPawnshop, int index, RandomHelper random) {
        List<PawnshopBidPrice> priceList = userPawnshopEvent.getPriceList();
        if (index >= priceList.size()) {
            index = priceList.size() - 1;
        }

        PawnshopBidPrice pawnshopBidPrice = priceList.get(index);
        userPawnshopEvent.setPatient(userPawnshopEvent.getPatient() - pawnshopBidPrice.getReducePatient());

        int randomNum = random.next(0, 100);
        int probability = pawnshopBidPrice.getProbability();
        ePawnshopEventStatusType status;
        userPawnshopEvent.setUserBid(pawnshopBidPrice.getPrice());
        if (randomNum < probability) {
            // 成交
            status = ePawnshopEventStatusType.DEAL;
        } else {
            if (userPawnshopEvent.getPatient() <= 0) {
                //没有耐心 放弃了
                status = ePawnshopEventStatusType.GIVE_UP;
            } else {
                status = ePawnshopEventStatusType.NORMAL;
                if (userPawnshopEvent.getType() == ePawnshopEventType.Sell.getValue()) {
                    PawnshopMgr.sellEventResetPrice(userPawnshop, userPawnshopEvent);
                    List<PawnshopBidPrice> bidPriceList = PawnshopMgr.sellBidPriceList(userPawnshop, userPawnshopEvent);
                    userPawnshopEvent.setPriceList(bidPriceList);
                } else {
                    PawnshopMgr.buyEventResetPrice(userPawnshop, userPawnshopEvent);
                    List<PawnshopBidPrice> bidPriceList = PawnshopMgr.buyBidPriceList(userPawnshop, userPawnshopEvent);
                    userPawnshopEvent.setPriceList(bidPriceList);
                }
            }
        }
        userPawnshopEvent.setStatus(status.getValue());
        return new PawnshopBidResult(pawnshopBidPrice.getPrice(), userPawnshopEvent.getStatus(), userPawnshopEvent.getPatient(), userPawnshopEvent.getPriceList());

    }


}
